package ooo.reindeer.data.util;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.util.internal.StringUtil;
import ooo.reindeer.data.annotation.*;
import ooo.reindeer.data.decoder.FixedLengthFrameDecoder;
import ooo.reindeer.data.decoder.IFrameDecoder;
import ooo.reindeer.data.decoder.LengthFieldBasedFrameDecoder;
import ooo.reindeer.data.option.Type;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import static ooo.reindeer.data.util.UnitVarUtil.getUintVarSize;

public class ByteDataUtil {

    static final Map<Class, Field[]> classFieldsMap = new ConcurrentHashMap<Class, Field[]>();
    static final Map<String, Field> classFieldMap = new ConcurrentHashMap<String, Field>();

    private static boolean conditionCheck(Object object, Field field) throws NoSuchFieldException, IllegalAccessException {
        Condition condition = field.getAnnotation(Condition.class);
        if (condition != null) {

            Field conditionField = getField(condition.clazz(), condition.condition());

            Object value = conditionField.get(object);
            for (long l : condition.value()) {
                if (DataUtil.compare(value, l)) {
                    return true;
                }
            }
            return false;
        } else {
            return true;
        }

    }

    private static <T> void deCode(ByteBuf byteBuf, Class<T> clazz, T object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {

        if (!clazz.getSuperclass().getName().equals(Object.class.getName())) {
            deCode(byteBuf, clazz.getSuperclass(), object);
        }
        for (Field field : getFields(clazz)) {
            try{
                toObject(byteBuf, object, field);
            } catch (Throwable t) {
                String message = object.getClass().getName() + ":\t" +
                        object + ":\t" + field.getName() + ":\t" + field.get(object) ;

                throw new RuntimeException(message, t);
            }
        }
    }

    private static Object deCode(ByteBuf byteBuf, Annotation ann, int length, Class calzz) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        Type type = (Type) getType(ann);
        return type.coder().deCode(byteBuf, ann, length, calzz);
    }

    private static void enCode(ByteBuf byteBuf, Class clazz, Object object, Map<Field, Integer> fieldWIndexMap) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

        if (!clazz.getSuperclass().getName().equals(Object.class.getName())) {
            enCode(byteBuf, clazz.getSuperclass(), object, fieldWIndexMap);
        }

        for (Field field : getFields(clazz)) {
            try {
                toBytes(byteBuf, object, field, fieldWIndexMap);
            } catch (Throwable t) {
                String message = object.getClass().getName() + ":\t" +
                        object + ":\t" + field.getName() + ":\t" + field.get(object) ;

                throw new RuntimeException(message, t);
            }
        }
    }

    private static void enCode(ByteBuf byteBuf, Object fieldObject, Annotation ann) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        Type type = (Type) getType(ann);
        type.coder().enCode(byteBuf, fieldObject, ann, fieldObject.getClass());

    }

    private static Field getField(Class clazz, String fieldName) throws NoSuchFieldException {
        String key = clazz.getName() + ":" + fieldName;
        Field field = classFieldMap.get(key);
        if (field == null) {
            field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            classFieldMap.put(key, field);
        }
        return field;
    }

    private static Field[] getFields(Class clazz) {
        Field[] fields = classFieldsMap.get(clazz);
        if (fields == null) {
            fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
            }
            classFieldsMap.put(clazz, fields);
        }
        return fields;
    }

    public static String getHexDump(byte[] byteBuf) {
        ByteBuf temp = ByteBufAllocator.DEFAULT.buffer();
        temp.writeBytes(byteBuf);
        String str = getHexDump(temp);
        temp.release();
        return str;
    }

    public static String getHexDump(ByteBuf byteBuf) {
        int length = byteBuf.readableBytes();
        int rows = length / 16 + (length % 15 == 0 ? 0 : 1) + 4;
        StringBuilder buf = new StringBuilder(2 + 10 + 1 + 2 + rows * 80);
        buf.append(length).append('B').append(StringUtil.NEWLINE);
        ByteBufUtil.appendPrettyHexDump(buf, byteBuf);
        return buf.toString();
    }

    public static DataReader getReader(InputStream inputStream, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) throws Exception {
        return getReader(inputStream, ByteOrder.BIG_ENDIAN, maxFrameLength, lengthFieldOffset, lengthFieldLength, 0, 0);
    }

    public static DataReader getReader(InputStream inputStream, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) throws Exception {
        return getReader(inputStream, ByteOrder.BIG_ENDIAN, maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip);
    }

    public static DataReader getReader(InputStream inputStream, ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) throws Exception {
        return getReader(inputStream, new LengthFieldBasedFrameDecoder(byteOrder, maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, true));
    }

    public static DataReader getReader(InputStream inputStream, IFrameDecoder frameDecoder) throws Exception {
        DataReader reader = new DataReader(inputStream, frameDecoder);
        return reader;
    }

    public static DataReader getReader(InputStream inputStream, int frameLength) throws Exception {
        DataReader reader = new DataReader(inputStream, new FixedLengthFrameDecoder(frameLength));
        return reader;
    }

    private static Object getType(Annotation ann) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {

        return AnnotationUtil.getTypeMethod(ann).invoke(ann);
//        return ann.annotationType().getDeclaredMethod("type").invoke(ann);
    }

    public static byte[] readMarkBytes(ByteBuf buf, byte[] startMark, byte[] endMark) {
        byte[] bytes;
        for (byte b : startMark) {
            if (buf.readByte() != b) {
                {
                    throw new RuntimeException("unknown start mark");
                }
            }
        }
        buf.markReaderIndex();
        int index = 1;
        int endMarkIndex = 0;
        boolean end = false;
        byte temp;
        while (true) {

            temp = buf.readByte();
            if (endMark[endMarkIndex] == temp) {
                endMarkIndex++;
            } else {
                endMarkIndex = 0;

            }

            index++;

            if ((endMark.length - 1) == endMarkIndex) {
                break;
            }

        }

        int length = index - endMark.length;
        bytes = new byte[length];
        buf.resetReaderIndex();
        buf.readBytes(bytes);
        buf.skipBytes(endMark.length);
        return bytes;
    }

    public static byte[] toBytesEx(Object object) {
//        System.out.println("ByteDataUtil.toBytesEx( "+"object = [" + object + "]"+" )");

        ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer();
        try {
            return toBytesEx(buffer, object);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            buffer.release();
        }
    }

    private static void toBytesEx(CompositeByteBuf byteBuf, Class clazz, Object object, Map<Field, Integer> fieldWIndexMap) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//        System.out.println("ByteDataUtil.toBytesEx( "+"byteBuf = [" + byteBuf + "], clazz = [" + clazz + "], object = [" + object + "], fieldWIndexMap = [" + fieldWIndexMap + "]"+" )");

        if (!clazz.getSuperclass().getName().equals(Object.class.getName())) {
            toBytesEx(byteBuf, clazz.getSuperclass(), object, fieldWIndexMap);
        }

        for (Field field : getFields(clazz)) {
            toBytesEx(byteBuf, object, field, fieldWIndexMap);
        }
    }

    private static void toBytesEx(ByteBuf byteBuf, Object fieldObject, Annotation ann) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        Type type = (Type) getType(ann);
        type.coder().enCode(byteBuf, fieldObject, ann, fieldObject.getClass());
//        System.out.println("ByteBufUtil.hexDump(byteBuf) = " + ByteBufUtil.hexDump(byteBuf));

    }

    private static void toBytesEx(CompositeByteBuf byteBuf, Object object, Field field, Map<Field, Integer> fieldIntegerMap) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

        int thisComponentIndex = fieldIntegerMap.computeIfAbsent(field, t -> byteBuf.numComponents());
//        System.out.println("field name["+thisComponentIndex+"]:"+field.getName());

        if (!conditionCheck(object, field)) {
            return;
        }

        Annotation ann = AnnotationUtil.getAnnotation(field.getAnnotations());

        if (ann != null) {

            Object fieldObject = field.get(object);

            if (fieldObject == null) {
                fieldObject = DataUtil.defaultValue(field.getType());
            }

            int oldWIndex = byteBuf.writerIndex();
            Array arrayFieldAnnotation = field.getAnnotation(Array.class);
            if (arrayFieldAnnotation != null) {

                List list = (List) fieldObject;

                ByteBuf buf = ByteBufAllocator.DEFAULT.buffer();
                for (Object item : list) {
                    enCode(buf, item, ann);
                }
                byteBuf.addComponent(false, thisComponentIndex, buf);
                oldWIndex = byteBuf.writerIndex();
                Field sizeField = getField(arrayFieldAnnotation.clazz(), arrayFieldAnnotation.value());
                sizeField.set(object, DataUtil.convert(sizeField.getType(), list.size()));
                toBytesEx(byteBuf, object, sizeField, fieldIntegerMap);
            } else {
                if (byteBuf.numComponents() == thisComponentIndex) {
                    //写入新字段值
                    ByteBuf buf = ByteBufAllocator.DEFAULT.buffer();
                    toBytesEx(buf, fieldObject, ann);
                    byteBuf.addComponent(false, thisComponentIndex, buf);
                } else {
                    //修改对应字段编码值
                    toBytesEx(byteBuf.internalComponent(thisComponentIndex).clear(), fieldObject, ann);
                }
            }

            LengthField lengthFieldAnnotation = field.getAnnotation(LengthField.class);
            if (lengthFieldAnnotation != null) {
                int newWIndex = byteBuf.writerIndex();
                int fieldSize = newWIndex - oldWIndex;
                if (lengthFieldAnnotation.maxLength() < fieldSize + DataUtil.negate(lengthFieldAnnotation.revise())) {
                    throw new RuntimeException(String.format("%s overstep max length is %d < %d", field.getName(), lengthFieldAnnotation.maxLength(), (fieldSize + DataUtil.negate(lengthFieldAnnotation.revise()))));
                }

                Field sizeField = getField(lengthFieldAnnotation.clazz(), lengthFieldAnnotation.value());
                sizeField.set(object, DataUtil.convert(sizeField.getType(), fieldSize + DataUtil.negate(lengthFieldAnnotation.revise())));
                toBytesEx(byteBuf, object, sizeField, fieldIntegerMap);

            }

        }

    }


    private static void toBytesEx(CompositeByteBuf byteBuf, Object object) throws NoSuchFieldException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        final Map<Field, Integer> fieldWIndexMap = new HashMap<Field, Integer>();
        Class valueClass = object.getClass();
        int oldWIndex = byteBuf.writerIndex();
        if (!valueClass.getSuperclass().getName().equals(Object.class.getName())) {
            toBytesEx(byteBuf, valueClass.getSuperclass(), object, fieldWIndexMap);
        }

        for (Field field : getFields(valueClass)) {
            try {
                toBytesEx(byteBuf, object, field, fieldWIndexMap);
            } catch (Throwable t) {
                String message = object.getClass().getName() + ":\t" +
                        object + ":\t" + field.getName() + ":\t" + field.get(object) ;

                throw new RuntimeException(message, t);
            }
        }


//        toBytesEx(byteBuf, object.getClass(), object, fieldWIndexMap);
        int newWIndex = byteBuf.writerIndex();
        int size = newWIndex - oldWIndex;
        LengthField lengthFieldAnnotation = (LengthField) valueClass.getAnnotation(LengthField.class);
        if (lengthFieldAnnotation != null) {
            if (lengthFieldAnnotation.maxLength() < size + DataUtil.negate(lengthFieldAnnotation.revise())) {
                throw new RuntimeException(String.format("%s overstep max length is %d < %d", object.getClass().getName(), lengthFieldAnnotation.maxLength(), (size + DataUtil.negate(lengthFieldAnnotation.revise()))));
            }
            Field sizeField = getField(lengthFieldAnnotation.clazz(), lengthFieldAnnotation.value());

            if (sizeField.getAnnotation(UnsignedIntVar.class) != null) {

                reCountClassSize(object, sizeField, size, lengthFieldAnnotation);
                toBytesEx(byteBuf, object, sizeField, fieldWIndexMap);
            } else {
                sizeField.set(object, size + DataUtil.negate(lengthFieldAnnotation.revise()));
                toBytesEx(byteBuf, object, sizeField, fieldWIndexMap);
            }
        }
    }

    public static byte[] toBytesEx(ByteBuf byteBuf, Object object) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        CompositeByteBuf buf = CompositeByteBuf.newInstance();
        toBytesEx(buf, object);
        ByteBuf swapBuf = buf.toByteBuf();
        byteBuf.writeBytes(swapBuf);
        swapBuf.release();
        return ByteBufUtil.getBytes(byteBuf);
    }

    public static byte[] toBytes(ByteBuf byteBuf, Object object) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        writeByteBuf(byteBuf, object);
        return ByteBufUtil.getBytes(byteBuf);
    }


    private static void toBytes(ByteBuf byteBuf, Object object, Field field, Map<Field, Integer> fieldIntegerMap) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//       field.setAccessible(true);
        if (!conditionCheck(object, field)) {
            return;
        }


        Annotation ann = AnnotationUtil.getAnnotation(field.getAnnotations());

        if (ann != null) {

            Object fieldObject = field.get(object);

            if (fieldObject == null) {
                fieldObject = DataUtil.defaultValue(field.getType());
            }

            int oldWIndex = byteBuf.writerIndex();

            Array arrayFieldAnnotation = field.getAnnotation(Array.class);
            if (arrayFieldAnnotation != null) {

                List objs = (List) fieldObject;


                for (Object obj : objs) {
                    enCode(byteBuf, obj, ann);
                }

                oldWIndex = byteBuf.writerIndex();
                Field sizeField = getField(arrayFieldAnnotation.clazz(), arrayFieldAnnotation.value());

                if (sizeField.getAnnotation(UnsignedIntVar.class) != null) {

                    sizeField.set(object, DataUtil.convert(sizeField.getType(), objs.size()));
                    //创建需要移动的数据
                    byte[] moveBytes = new byte[oldWIndex - UnsignedIntVar.DEFAULT_SIZE - fieldIntegerMap.get(sizeField)];
                    //拷贝数据
                    byteBuf.getBytes(fieldIntegerMap.get(sizeField) + UnsignedIntVar.DEFAULT_SIZE, moveBytes);
                    //重新设定写入索引到长度字段起始位置
                    byteBuf.writerIndex(fieldIntegerMap.get(sizeField));
                    //写入长度字段到数据流中
                    toBytes(byteBuf, object, sizeField, fieldIntegerMap);
                    //将需要移动的数据协会数据流中
                    byteBuf.writeBytes(moveBytes);
                } else {
                    byteBuf.writerIndex(fieldIntegerMap.get(sizeField));

//                sizeField.setAccessible(true);
                    sizeField.set(object, DataUtil.convert(sizeField.getType(), objs.size()));
                    toBytes(byteBuf, object, sizeField, fieldIntegerMap);
                    byteBuf.writerIndex(oldWIndex);
                }

            } else {

                enCode(byteBuf, fieldObject, ann);
            }

            int newWIndex = byteBuf.writerIndex();
            int fieldSize = newWIndex - oldWIndex;
            fieldIntegerMap.put(field, oldWIndex);
            LengthField lengthFieldAnnotation = field.getAnnotation(LengthField.class);
            if (lengthFieldAnnotation != null) {

                if (lengthFieldAnnotation.maxLength() < fieldSize + DataUtil.negate(lengthFieldAnnotation.revise())) {
                    throw new RuntimeException(String.format("%s overstep max length is %d < %d", field.getName(), lengthFieldAnnotation.maxLength(), (fieldSize + DataUtil.negate(lengthFieldAnnotation.revise()))));
                }

                oldWIndex = byteBuf.writerIndex();
                Field lengthField = getField(lengthFieldAnnotation.clazz(), lengthFieldAnnotation.value());

                if (lengthField.getAnnotation(UnsignedIntVar.class) != null) {

                    reCountFieldSize(object, lengthField, fieldSize, lengthFieldAnnotation);
                    //创建需要移动的数据
                    byte[] moveBytes = new byte[newWIndex - UnsignedIntVar.DEFAULT_SIZE - fieldIntegerMap.get(lengthField)];
                    //拷贝数据
                    byteBuf.getBytes(fieldIntegerMap.get(lengthField) + UnsignedIntVar.DEFAULT_SIZE, moveBytes);
                    //重新设定写入索引到长度字段起始位置
                    byteBuf.writerIndex(fieldIntegerMap.get(lengthField));
                    //写入长度字段到数据流中
                    toBytes(byteBuf, object, lengthField, fieldIntegerMap);
                    //将需要移动的数据协会数据流中
                    byteBuf.writeBytes(moveBytes);

                } else {

//                Field lengthField = lengthFieldAnnotation.clazz().getDeclaredField(lengthFieldAnnotation.value());
                    byteBuf.writerIndex(fieldIntegerMap.get(lengthField));
//                lengthField.setAccessible(true);

                    lengthField.set(object, DataUtil.convert(lengthField.getType(), fieldSize + DataUtil.negate(lengthFieldAnnotation.revise())));
                    toBytes(byteBuf, object, lengthField, fieldIntegerMap);
                    byteBuf.writerIndex(oldWIndex);
                }
            }
        }
    }

    private static void reCountClassSize(Object object, Field field, int fieldSize, LengthField lengthFieldAnnotation) throws IllegalAccessException {
        //判断是否对长度字段进行调整
        if (UnsignedIntVar.AUTO_SIZE == lengthFieldAnnotation.revise()) {
            //调整自动长度
            //获取不包含长度字段的数据长度
            int srcSize = fieldSize - UnsignedIntVar.DEFAULT_SIZE;
            //获取变长整型的长度
            int uintVarSize = getUintVarSize(srcSize);
            //设置对象变长整型的值(不包含变长字段的数据长度)
            field.set(object, srcSize);

        } else {
            //调整固定长度
            //获取不包含长度字段的数据长度
            int srcSize = fieldSize - UnsignedIntVar.DEFAULT_SIZE;
            //获取变长整型的长度
            int uintVarSize = getUintVarSize(srcSize);
            int totalLength = srcSize + uintVarSize + DataUtil.negate(lengthFieldAnnotation.revise());
            totalLength = (uintVarSize == getUintVarSize(totalLength)) ? totalLength : (srcSize + getUintVarSize(totalLength));
            //设置对象变长整型的值(不包含变长字段的数据长度)
            field.set(object, totalLength);
        }
    }

    private static void reCountFieldSize(Object object, Field field, int fieldSize, LengthField lengthFieldAnnotation) throws IllegalAccessException {
        //判断是否对长度字段进行调整
        if (UnsignedIntVar.AUTO_SIZE == lengthFieldAnnotation.revise()) {
//            //调整自动长度
//            //获取不包含长度字段的数据长度
//            int srcSize= fieldSize;
//            //设置对象变长整型的值(不包含变长字段的数据长度)
//            field.set(object, srcSize);
            throw new UnsupportedOperationException("not support auto size");

        } else {
            //调整固定长度
            //获取不包含长度字段的数据长度
            int srcSize = fieldSize;
            //获取变长整型的长度
            int finalSize = srcSize + DataUtil.negate(lengthFieldAnnotation.revise());
            //设置对象变长整型的值(不包含变长字段的数据长度)
            field.set(object, finalSize);
        }
    }


    public static byte[] toBytes(Object object) {
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
        try {
            return toBytes(byteBuf, object);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            byteBuf.release();
        }
    }

    public static <T> T toObject(ByteBuf byteBuf, Class<T> clazz) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        T object = clazz.newInstance();
        if (clazz.getAnnotation(VirtualRead.class) != null) {
            byteBuf.markReaderIndex();
            deCode(byteBuf, clazz, object);
            byteBuf.resetReaderIndex();
        } else {
            deCode(byteBuf, clazz, object);
        }

//        LengthField lengthFieldAnnotation = clazz.getAnnotation(LengthField.class);
//        lengthFieldAnnotation.clazz().getf

        return object;

    }

    private static void toObject(ByteBuf byteBuf, Object object, Field field) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
//        field.setAccessible(true);

        if (!conditionCheck(object, field)) {
            return;
        }

        Annotation ann = AnnotationUtil.getAnnotation(field.getAnnotations());

        if (ann != null) {

            Object value = null;
            Array arrayFieldAnnotation = field.getAnnotation(Array.class);
            if (arrayFieldAnnotation != null) {
                List list = new ArrayList();
                Field sizeField = getField(arrayFieldAnnotation.clazz(), arrayFieldAnnotation.value());
//                Field sizeField = arrayFieldAnnotation.clazz().getDeclaredField(arrayFieldAnnotation.value());
                Integer size = (Integer) DataUtil.convert(Integer.class, sizeField.get(object));
                Class clazz = null;

                if (ann instanceof Struct) {
                    clazz = ((Struct) ann).classType();
                } else {
                    clazz = field.getType();

                }

                for (Integer i = 0; i < size; i++) {
                    list.add(deCode(byteBuf, ann, Type.AUTO_LENGTH, clazz));
                }
                value = list;
            } else {
                LengthField lengthFieldAnnotation = field.getAnnotation(LengthField.class);
                if (lengthFieldAnnotation != null) {
                    Field lengthField = getField(lengthFieldAnnotation.clazz(), lengthFieldAnnotation.value());
//                    Field lengthField = lengthFieldAnnotation.clazz().getDeclaredField(lengthFieldAnnotation.value());
                    int length = (Integer) DataUtil.convert(Integer.class, lengthField.get(object));
                    length = length + ((lengthFieldAnnotation.revise() == UnsignedIntVar.AUTO_SIZE) ? getUintVarSize(length) : DataUtil.negate(lengthFieldAnnotation.revise()));

                    if (lengthFieldAnnotation.maxLength() < length) {
                        throw new RuntimeException(String.format("%s overstep max length is %d < %d", field.getName(), lengthFieldAnnotation.maxLength(), length));
                    }

                    value = deCode(byteBuf, ann, length, field.getType());

                } else {

                    value = deCode(byteBuf, ann, Type.AUTO_LENGTH, field.getType());

                }
            }

            field.set(object, value);
            return;
        }

    }

    public static <T> T toObject(byte[] bytes, Class<T> clazz) {
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
        byteBuf.writeBytes(bytes);
        try {
            return toObject(byteBuf, clazz);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            byteBuf.release();
        }
    }

    public static void write(OutputStream output, Object object) throws IOException {
        byte[] bytes = toBytes(object);
        output.write(bytes);
    }

    public static void writeByteBuf(ByteBuf byteBuf, Object object) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Map<Field, Integer> fieldWIndexMap = new HashMap<Field, Integer>();
        LengthField lengthFieldAnnotation = object.getClass().getAnnotation(LengthField.class);
        int oldWIndex = byteBuf.writerIndex();
        enCode(byteBuf, object.getClass(), object, fieldWIndexMap);
        int newWIndex = byteBuf.writerIndex();
        int size = newWIndex - oldWIndex;
        if (lengthFieldAnnotation != null) {
            if (lengthFieldAnnotation.maxLength() < size + DataUtil.negate(lengthFieldAnnotation.revise())) {
                throw new RuntimeException(String.format("%s overstep max length is %d < %d", object.getClass().getName(), lengthFieldAnnotation.maxLength(), (size + DataUtil.negate(lengthFieldAnnotation.revise()))));
            }
            Field field = getField(lengthFieldAnnotation.clazz(), lengthFieldAnnotation.value());
            if (field.getAnnotation(UnsignedIntVar.class) != null) {

                //判断是否对长度字段进行调整
                reCountClassSize(object, field, size, lengthFieldAnnotation);
                //创建需要移动的数据
                byte[] moveBytes = new byte[size - UnsignedIntVar.DEFAULT_SIZE - fieldWIndexMap.get(field)];
                //拷贝数据
                byteBuf.getBytes(fieldWIndexMap.get(field) + UnsignedIntVar.DEFAULT_SIZE, moveBytes);
                //重新设定写入索引到长度字段起始位置
                byteBuf.writerIndex(fieldWIndexMap.get(field));
                //写入长度字段到数据流中
                toBytes(byteBuf, object, field, fieldWIndexMap);
                //将需要移动的数据协会数据流中
                byteBuf.writeBytes(moveBytes);
            } else {
                field.set(object, size + DataUtil.negate(lengthFieldAnnotation.revise()));
                byteBuf.writerIndex(fieldWIndexMap.get(field));
                toBytes(byteBuf, object, field, fieldWIndexMap);
                byteBuf.writerIndex(newWIndex);
            }
        }
    }


    private static byte[] hexStringToByteArray(String hexString) {
        int len = hexString.length();
        byte[] byteArray = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            byteArray[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i+1), 16));
        }
        return byteArray;
    }

    public static byte[] getBytesByHexDump(String hex){
        hex=hex.substring(hex.indexOf("|00000000|"),hex.lastIndexOf("|")+1);
        System.out.println(hex);
        String tempHex="";
        for (String s : hex.split("\n")) {
            tempHex += s.substring(s.indexOf('|', 1) + 1, s.indexOf('|', 10)).replaceAll("\\s+", "");
        }
        return hexStringToByteArray(tempHex);
    }

    static final char[] hexArray = "0123456789ABCDEF".toCharArray();
    public static String bytesToHex(byte[] bytes) {

        char[] hexChars = new char[bytes.length * 2];
        for (int i = 0; i < bytes.length; i++) {
            int v = bytes[i] & 0xFF;
            hexChars[i * 2] = hexArray[v >>> 4];
            hexChars[i * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    public static byte[] hexToBytes(String hexString) {
        if (hexString.length() % 2 != 0) {
            throw new IllegalArgumentException("Invalid hexadecimal string");
        }
        ByteBuffer byteBuffer = ByteBuffer.allocate(hexString.length() / 2);
        for (int i = 0; i < hexString.length(); i += 2) {
            byteBuffer.put((byte) Integer.parseInt(hexString.substring(i, i + 2), 16));
        }
        return byteBuffer.array();
    }


    static class CompositeByteBuf {

        public static CompositeByteBuf newInstance() {
            return new CompositeByteBuf();
        }

        /**
         * 字节缓冲区列表
         */
        List<ByteBuf> byteBufList = new ArrayList<ByteBuf>();

        final AtomicInteger writerIndex = new AtomicInteger(0);

        public List<ByteBuf> getByteBufList() {
            return byteBufList;
        }

        public ByteBuf internalComponent(int index) {
            return byteBufList.get(index);
        }

        public void release() {
            for (ByteBuf byteBuf : byteBufList) {
                byteBuf.release();
            }
        }

        public CompositeByteBuf setByteBufList(List<ByteBuf> byteBufList) {
            this.byteBufList = byteBufList;
            return this;
        }

        public int writerIndex() {
            updateWriteIndex();
            return writerIndex.get();
        }

        public int numComponents() {
            return byteBufList.size();
        }

        public void addComponent(boolean updateWriteIndex, int index, ByteBuf byteBuf) {
            byteBufList.add(index, byteBuf);
            if (updateWriteIndex) {
                updateWriteIndex();
            }
        }

        public void addComponent(boolean updateWriteIndex, ByteBuf byteBuf) {
            byteBufList.add(byteBuf);
            if (updateWriteIndex) {
                updateWriteIndex();
            }
        }

        public void updateWriteIndex() {
            int index = 0;
            for (ByteBuf byteBuf : byteBufList) {
                index += byteBuf.writerIndex();
            }
            writerIndex.set(index);
        }

        public ByteBuf toByteBuf() {
            io.netty.buffer.CompositeByteBuf buf = ByteBufAllocator.DEFAULT.compositeBuffer();
            buf.addComponents(true, byteBufList);
            return buf;
        }

    }

}
